﻿using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Common.NPOI
{
    /// <summary>
    /// EXCEL表格
    /// </summary>
    public class ExcelSheet<T> : ExcelBase
    {
        private readonly IEnumerable<T> dataList;
        private IEnumerable<ExcelSheetContext> contexts;
        private PropertyInfo[] properties;
        private Type typeOfT;
        /// <summary>
        /// EXCEL表格
        /// </summary>
        /// <param name="table"></param>
        /// <param name="contexts"></param>

        /// <summary>
        /// EXCEL表格
        /// </summary>
        /// <param name="datalist"></param>
        /// <param name="contexts"></param>
        public ExcelSheet(IEnumerable<T> datalist, IEnumerable<ExcelSheetContext> contexts = null)
        {
            this.dataList = datalist;
            this.InitializeTypeInfo();
            this.contexts = contexts ?? BuildContexts();
        }
        private void InitializeTypeInfo()
        {
            this.typeOfT = typeof(T);
            if (this.typeOfT == typeof(object))
            {
                this.typeOfT = dataList.First().GetType();
            }
            this.properties = this.typeOfT.GetProperties(BindingFlags.Instance | BindingFlags.Public);
        }
        private IEnumerable<ExcelSheetContext> BuildContexts()
        {
            List<ExcelSheetContext> contexts = new List<ExcelSheetContext>();
            for (var i = 0; i < properties.Length; i++)
            {
                var property = properties[i];
                var columnSetup = property.GetCustomAttribute<NPOIExcelColumnAttribute>();
                ExcelSheetContext ctx = new ExcelSheetContext();
                ctx.Title = columnSetup?.Title ?? property.Name;
                ctx.ColumnName = property.Name;
                ctx.Order = columnSetup?.Order ?? i;
                ctx.Ignore = columnSetup?.Ignore ?? false;
                contexts.Add(ctx);
            }
            return contexts;
        }
        private ExcelSheetContext[] SortByOrder(ExcelSheetContext[] array)
        {
            for (int i = 0; i < array.Length; i++)
            {
                for (int j = i + 1; j < array.Length; j++)
                {
                    var npoi0 = array[i];
                    var npoi1 = array[j];
                    int range0 = i, range1 = j;
                    if (npoi0 != null && npoi0.Order > 0)
                    {
                        range0 = npoi0.Order;
                    }
                    if (npoi1 != null && npoi1.Order > 0)
                    {
                        range1 = npoi1.Order;
                    }
                    ExcelSheetContext temp = array[i];
                    if (range1 < range0)
                    {
                        array[i] = array[j];
                        array[j] = temp;
                    }
                }
            }
            return array;
        }
        /// <summary>
        /// 导出EXCEL到流
        /// </summary>
        /// <param name="stream"></param>
        public override void Export(Stream stream)
        {
            var columns = SortByOrder(contexts.ToArray());
            string sheetName = typeOfT.GetCustomAttribute<NPOIExcelAttribute>()?.SheetName ?? "sheet1";
            HSSFWorkbook hSSFWorkbook = new HSSFWorkbook();
            ISheet sheet = hSSFWorkbook.CreateSheet(sheetName);
            IRow head_row = sheet.GetRow(0) ?? sheet.CreateRow(0);
            head_row.HeightInPoints = 20;
            var index = 0;
            foreach (var item in columns)
            {
                string titlename = string.IsNullOrEmpty(item.Title) ? item.ColumnName : item.Title;
                if (string.IsNullOrEmpty(titlename))
                {
                    continue;
                }

                ICell cell = head_row.CreateCell(index);
                cell.SetCellValue(titlename);
                cell.CellStyle = GetTitleStyle(hSSFWorkbook);

                index++;
            }
            int rowIndex = 1;
            //单元格
            foreach (var item in dataList)
            {
                IRow row2 = sheet.GetRow(rowIndex) ?? sheet.CreateRow(rowIndex);
                row2.HeightInPoints = 20;

                for (int k = 0; k < columns.Length; k++)
                {
                    var col = columns[k];
                    var title = string.IsNullOrEmpty(col.Title) ? col.ColumnName : col.Title;
                    var val = this.properties.First(p => p.Name == col.ColumnName).GetValue(item);
                    ICell cell2 = row2.CreateCell(k);
                    cell2.CellStyle = GetCellStyle(hSSFWorkbook);
                    int num = Encoding.Default.GetByteCount(title);
                    if (val != null)
                    {
                        num = Encoding.Default.GetByteCount(val.ToString()) > Encoding.Default.GetByteCount(title) ?
                            Encoding.Default.GetByteCount(val.ToString()) :
                            Encoding.Default.GetByteCount(title);
                    }
                    sheet.SetColumnWidth(k, (num + 1) * 256);
                    object value = col.Convert(val);
                    if (value == null)
                    {
                        SetCellValue(cell2, string.Empty, typeof(string));
                    }
                    else
                    {
                        SetCellValue(cell2, value, value.GetType());
                    }
                }
                rowIndex++;
            }
            hSSFWorkbook.Write(stream);
            //hSSFWorkbook.Dispose();
            hSSFWorkbook.Close();
        }
    }
}